// Copyright©,2020-2025
// Author: caocheng
// Version: 1.0.0
// Date: 2021/3/15 10:02
// Description：
package SummerBoot

import (
	"gitee.com/chrischo/go-summer/summer/summer-scanner"
	"gitee.com/chrischo/go-summer/summer/summer-utils"
	"gitee.com/chrischo/go-summer/summer/summer-web"
	"path/filepath"
	"reflect"
	"strings"
)

// CtrlFuncHandler BIND 形式的 Web 处理接口
type CtrlFuncHandler struct {
	fn      interface{}
	fnType  reflect.Type
	fnValue reflect.Value
}

func (b *CtrlFuncHandler) Invoke(ctx SummerWeb.WebContext) {
	// 执行处理函数，并返回结果
	in := []reflect.Value{reflect.ValueOf(ctx)}
	b.fnValue.Call(in)
}

func (b *CtrlFuncHandler) FileLine() (file string, line int, fnName string) {
	return SummerUtils.FileLine(b.fn)
}

type RouteMethod struct {
	Path       string
	Method     uint32
	Handler    SummerWeb.Handler
	StructName string
	Comment    SummerScanner.Comment
}

type ControllerScanner struct {
	controllers map[string]interface{}
}

func NewControllerScanner() *ControllerScanner {
	return &ControllerScanner{
		controllers: make(map[string]interface{}),
	}
}

func (s *ControllerScanner) Scanner(controller interface{}) []RouteMethod {

	tof := reflect.TypeOf(controller)
	vof := reflect.ValueOf(controller)

	//type 取得指针
	tof = SummerUtils.Indirect(tof)
	s.controllers[tof.Name()] = controller

	//获取controller文件路径
	pkgpath := tof.PkgPath()
	pos := strings.Index(pkgpath, "/")
	path := pkgpath[pos+1:]
	filepath := filepath.Join(path, tof.Name()+".go")

	//扫描controller go文件
	scanner := SummerScanner.NewGoFileScanner()
	scanner.ParseFile(filepath)
	methods := scanner.GetMethods(tof.Name())

	//通过扫描获取controller相关路由信息
	return s.parserRouteMethod(vof, methods)
}

func (s *ControllerScanner) parserRouteMethod(vof reflect.Value, methods []SummerScanner.Method) []RouteMethod {
	var routeMethods []RouteMethod
	for _, method := range methods {
		parser := SummerScanner.NewCommentParser()
		comment := parser.ParserComments(method.Comments)
		for _, v := range comment.Router.Methods {
			var routeMethod RouteMethod
			routeMethod.Path = comment.Router.Path
			value := vof.MethodByName(method.MethodName)
			routeMethod.Handler = &CtrlFuncHandler{
				fn:      value.Interface(),
				fnType:  reflect.TypeOf(value.Interface()),
				fnValue: reflect.ValueOf(value.Interface()),
			}
			routeMethod.Method = s.mapWebMethod(v)
			routeMethod.Comment = comment
			routeMethod.StructName = method.StructName
			routeMethods = append(routeMethods, routeMethod)
		}
	}
	return routeMethods
}

func (s *ControllerScanner) mapWebMethod(method string) uint32 {
	switch method {
	case "GET":
		return SummerWeb.MethodGet
	case "POST":
		return SummerWeb.MethodPost
	case "HEAD":
		return SummerWeb.MethodHead
	case "PUT":
		return SummerWeb.MethodPut
	case "PATCH":
		return SummerWeb.MethodPatch
	case "DELETE":
		return SummerWeb.MethodDelete
	case "CONNECT":
		return SummerWeb.MethodConnect
	case "OPTIONS":
		return SummerWeb.MethodOptions
	case "TRACE":
		return SummerWeb.MethodTrace
	case "ANY":
		return SummerWeb.MethodAny
	default:
		return SummerWeb.MethodGet
	}
}
